package com.xhsj.user.generalprocess.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhsj.user.generalprocess.entity.TbPamGeneralNode;
import com.xhsj.user.generalprocess.entity.TbPamGeneralOpinionFile;
import com.xhsj.user.generalprocess.entity.TbPamGeneralProcessHiTask;
import com.xhsj.user.generalprocess.entity.TbPamGeneralProcessTask;
import com.xhsj.user.generalprocess.factory.GeneralProcessFactory;
import com.xhsj.user.generalprocess.mapper.TbPamGeneralNodeMapper;
import com.xhsj.user.generalprocess.mapper.TbPamGeneralOpinionFileMapper;
import com.xhsj.user.generalprocess.mapper.TbPamGeneralProcessHiTaskMapper;
import com.xhsj.user.generalprocess.mapper.TbPamGeneralProcessTaskMapper;
import com.xhsj.user.generalprocess.vo.*;
import com.xhsj.user.hr.system.mapper.TbGlobalUserMapper;
import com.xhsj.user.utils.IdGen;
import com.xhsj.user.utils.StringUtils;
import com.xhsj.user.utils.UserUtils;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * 通用流程任务表 服务实现类
 * </p>
 *
 * @author suxiaolin
 * @since Jan 21, 2021 11:10:35 AM
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class TbPamGeneralProcessTaskService extends ServiceImpl<TbPamGeneralProcessTaskMapper, TbPamGeneralProcessTask> {
    @Autowired
    private TbPamGeneralProcessTaskMapper tbPamGeneralProcessTaskMapper;

    @Autowired
    private TbPamGeneralProcessHiTaskMapper tbPamGeneralProcessHiTaskMapper;

    @Autowired
    private TbPamGeneralNodeMapper tbPamGeneralNodeMapper;

    @Autowired
    private TbPamGeneralOpinionFileMapper tbPamGeneralOpinionFileMapper;

    @Autowired
    private TbGlobalUserMapper tbGlobalUserMapper;


    /**
     * 启动流程
     *
     * @author 苏小林
     * @date 2021/1/22 13:38
     * @param: generalAuditVo
     */
    public void startProcess(GeneralAuditVo generalAuditVo, GeneralProcessFactory<?> factory) throws Exception {
        this.checkParm(generalAuditVo);

        String processType = generalAuditVo.getProcessType();
        int nodeType = 1;// 开始节点
        // 1.查询开始节点
        TbPamGeneralNode tbPamGeneralNode = tbPamGeneralNodeMapper.getStartNode(nodeType, processType, generalAuditVo.getNodeTableName());
        if (tbPamGeneralNode == null) {
            throw new Exception("初始节点为空");
        }
        TbPamGeneralNode nextNode = tbPamGeneralNodeMapper.getCurrNode(tbPamGeneralNode.getNextNode(), processType, generalAuditVo.getNodeTableName(), 0);

        // 2.保存开始节点任务到历史任务表
        generalAuditVo.setNodeId(tbPamGeneralNode.getNodeId());
        TbPamGeneralProcessHiTask hisTask = new TbPamGeneralProcessHiTask();
        hisTask.setUserId(UserUtils.getLoginAppUser().getUserId());
        hisTask.setExamineStatus(1);
        hisTask.setId(IdGen.snowId());
        this.saveHistory(generalAuditVo, hisTask);

        // 保存下一节点任务
        generalAuditVo.setNodeId(nextNode.getNodeId());
        this.saveTask(generalAuditVo);

        GeneralCallableVo generalCallableVo = new GeneralCallableVo();
        generalCallableVo.setNodeId(nextNode.getNodeId());
        generalCallableVo.setNodeName(nextNode.getNodeName());
        generalCallableVo.setProcessTaskId(generalAuditVo.getProcessTaskId());
        factory.callBack(generalCallableVo);

    }

    /**
     * 流程处理
     *
     * @author 苏小林
     * @date 2021/1/22 13:41
     * @param: generalAuditVo
     */
    public void handleProcess(GeneralAuditVo generalAuditVo, GeneralProcessFactory<?> factory) throws Exception {
        this.checkParm(generalAuditVo);
        // 1.删除当前正在执行流程
        Long processTaskId = generalAuditVo.getProcessTaskId();
        tbPamGeneralProcessTaskMapper.delById(processTaskId, generalAuditVo.getTaskTableName());

        // 2.修改历史任务执行状态
        updateHiTask(generalAuditVo, processTaskId);

        // 3.保存意见文件
        saveOpinionFile(generalAuditVo);

        // 4. 保存下一节点任务
        // 查询当前节点id
        TbPamGeneralNode currNode = tbPamGeneralNodeMapper.getCurrNode(generalAuditVo.getNodeId(), generalAuditVo.getProcessType(), generalAuditVo.getNodeTableName(), generalAuditVo.getStatus());

        // 查询下一个节点
        TbPamGeneralNode tbPamGeneralNode = tbPamGeneralNodeMapper.getCurrNode(currNode.getNextNode(), generalAuditVo.getProcessType(), generalAuditVo.getNodeTableName(), 0);

        if (tbPamGeneralNode == null) {
            throw new Exception("下一节点为空");
        }

        generalAuditVo.setOpinionText("");
        generalAuditVo.setNodeId(tbPamGeneralNode.getNodeId());
        if (tbPamGeneralNode.getNodeType() == 3) { // 结束
            TbPamGeneralProcessHiTask hisTask = new TbPamGeneralProcessHiTask();
            hisTask.setUserId(UserUtils.getLoginAppUser().getUserId());
            hisTask.setId(IdGen.snowId());
            hisTask.setExamineStatus(1);
            this.saveHistory(generalAuditVo, hisTask);

        } else {
            this.saveTask(generalAuditVo);
        }

        GeneralCallableVo generalCallableVo = new GeneralCallableVo();
        generalCallableVo.setNodeId(tbPamGeneralNode.getNodeId());
        generalCallableVo.setNodeName(tbPamGeneralNode.getNodeName());
        generalCallableVo.setProcessTaskId(generalAuditVo.getProcessTaskId());
        factory.callBack(generalCallableVo);


    }

    /**
     * 保存意见文件
     *
     * @author 苏小林
     * @date 2021/1/22 13:59
     * @param: processTaskId
     * @param: generalAuditVo
     */
    private void saveOpinionFile(GeneralAuditVo generalAuditVo) {
        List<TbPamGeneralOpinionFile> opinionFiles = generalAuditVo.getOpinionFiles();
        if (opinionFiles != null && opinionFiles.size() > 0) {

            for (TbPamGeneralOpinionFile opinionFile : opinionFiles) {
                opinionFile.setHisTaskId(generalAuditVo.getProcessTaskId());
                opinionFile.setCreateBy(UserUtils.getLoginAppUser().getUserId());
                opinionFile.setCreateDate(new Date());
                opinionFile.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
                opinionFile.setUpdateDate(new Date());
                tbPamGeneralOpinionFileMapper.save(opinionFile, generalAuditVo.getOpinionFileTableName());
            }
        }

    }

    /**
     * 修改历史任务执行状态
     *
     * @author 苏小林
     * @date 2021/1/22 13:58
     * @param: generalAuditVo
     * @param: processTaskId
     */
    private void updateHiTask(GeneralAuditVo generalAuditVo, Long processTaskId) {
        TbPamGeneralProcessHiTask hiTask = new TbPamGeneralProcessHiTask();
        hiTask.setId(processTaskId);
        hiTask.setUserId(UserUtils.getLoginAppUser().getUserId());
        hiTask.setRoleId(null);
        hiTask.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
        hiTask.setUpdateDate(new Date());
        hiTask.setRemarks(generalAuditVo.getOpinionText());
        hiTask.setExamineStatus(1);
        if (generalAuditVo.getStatus() == 1) {
            hiTask.setExamineStatus(2);
        }
        tbPamGeneralProcessHiTaskMapper.updateById(hiTask, generalAuditVo.getHiTaskTableName());
    }

    /**
     * 保存正在执行任务
     *
     * @author 苏小林
     * @date 2021/1/22 11:23
     * @param: generalAuditVo
     */
    private void saveTask(GeneralAuditVo generalAuditVo) throws Exception {
        List<Long> userIds = generalAuditVo.getUserIds();
        List<Long> roleIds = generalAuditVo.getRoleIds();
        if (userIds != null) {
            for (Long userId : userIds) {
                TbPamGeneralProcessTask processTask = new TbPamGeneralProcessTask();
                processTask.setNodeId(generalAuditVo.getNodeId());
                processTask.setDataId(generalAuditVo.getDataId());
                processTask.setUserId(userId);
                processTask.setCreateBy(UserUtils.getLoginAppUser().getUserId());
                processTask.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
                processTask.setCreateDate(new Date());
                processTask.setUpdateDate(new Date());
                processTask.setProcessType(generalAuditVo.getProcessType());
                int i = tbPamGeneralProcessTaskMapper.saveTask(processTask, generalAuditVo.getTaskTableName());
                if (i == 0) {
                    throw new Exception("保存正在执行任务出错");
                }

                TbPamGeneralProcessHiTask hisTask = new TbPamGeneralProcessHiTask();
                hisTask.setId(processTask.getId());
                hisTask.setExamineStatus(0);
                hisTask.setUserId(userId);
                generalAuditVo.setOpinionText("");
                generalAuditVo.setProcessTaskId(processTask.getId());
                this.saveHistory(generalAuditVo, hisTask);
            }
        }

        if (roleIds != null) {
            for (Long roleId : roleIds) {
                TbPamGeneralProcessTask processTask = new TbPamGeneralProcessTask();
                processTask.setNodeId(generalAuditVo.getNodeId());
                processTask.setDataId(generalAuditVo.getDataId());
                processTask.setRoleId(roleId);
                processTask.setCreateBy(UserUtils.getLoginAppUser().getUserId());
                processTask.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
                processTask.setCreateDate(new Date());
                processTask.setUpdateDate(new Date());
                processTask.setProcessType(generalAuditVo.getProcessType());
                int i = tbPamGeneralProcessTaskMapper.saveTask(processTask, generalAuditVo.getTaskTableName());
                if (i == 0) {
                    throw new Exception("保存正在执行任务出错");
                }

                TbPamGeneralProcessHiTask hisTask = new TbPamGeneralProcessHiTask();
                hisTask.setId(processTask.getId());
                hisTask.setExamineStatus(0);
                hisTask.setRoleId(roleId);
                generalAuditVo.setProcessTaskId(processTask.getId());
                generalAuditVo.setOpinionText("");
                this.saveHistory(generalAuditVo, hisTask);
            }
        }
    }

    /**
     * 保存历史任务
     *
     * @author 苏小林
     * @date 2021/1/22 11:23
     * @param: generalAuditVo
     */
    public void saveHistory(GeneralAuditVo generalAuditVo, TbPamGeneralProcessHiTask hiTask) throws Exception {
        hiTask.setNodeId(generalAuditVo.getNodeId());
        hiTask.setDataId(generalAuditVo.getDataId());
        hiTask.setProcessType(generalAuditVo.getProcessType());
        hiTask.setCreateBy(UserUtils.getLoginAppUser().getUserId());
        hiTask.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
        hiTask.setCreateDate(new Date(System.currentTimeMillis() + 1000));
        hiTask.setUpdateDate(new Date(System.currentTimeMillis() + 1000));
        hiTask.setRemarks(generalAuditVo.getOpinionText());
        int i = tbPamGeneralProcessHiTaskMapper.saveHistory(hiTask, generalAuditVo.getHiTaskTableName());
        if (i == 0) {
            throw new Exception("保存历史任务出错");
        }
    }

    /**
     * 检查参数
     *
     * @author 苏小林
     * @date 2021/1/22 17:20
     * @param: generalAuditVo
     */
    private void checkParm(GeneralAuditVo generalAuditVo) throws Exception {
        String nodeTableName = generalAuditVo.getNodeTableName();
        if (StringUtils.isBlank(nodeTableName)) {
            throw new Exception("节点表名不能为空");
        }

        String taskTableName = generalAuditVo.getTaskTableName();
        if (StringUtils.isBlank(taskTableName)) {
            throw new Exception("流程任务表名不能为空");
        }

        String hiTaskTableName = generalAuditVo.getHiTaskTableName();
        if (StringUtils.isBlank(hiTaskTableName)) {
            throw new Exception("历史任务表名不能为空");
        }


        String opinionFileTableName = generalAuditVo.getOpinionFileTableName();
        if (StringUtils.isBlank(opinionFileTableName)) {
            throw new Exception("流程意见表名不能为空");
        }

        String processType = generalAuditVo.getProcessType();
        if (StringUtils.isBlank(processType)) {
            throw new Exception("流程类型不能为空");
        }

    }


    /**
     * 查询正在运行中流程
     *
     * @author 苏小林
     * @date 2021/1/25 13:41
     * @param: generalAuditVo
     */
    public IPage<GeneralRunTaskVo> findRunTask(GeneralAuditVo generalAuditVo) throws Exception {
        this.checkParm(generalAuditVo);
        Page<GeneralRunTaskVo> page = new Page<>(generalAuditVo.getPage(), generalAuditVo.getSize());
        IPage<GeneralRunTaskVo> iPage = tbPamGeneralProcessTaskMapper.findRunTask(page, generalAuditVo);
        return iPage;

    }

    /**
     * 查询历史任务
     *
     * @author 苏小林
     * @date 2021/1/25 15:03
     * @param: generalAuditVo
     * @return: java.util.List<com.xhsj.user.generalprocess.vo.GeneralRunTaskVo>
     */
    public IPage<GeneralHiTaskVo> findHiTask(GeneralAuditVo generalAuditVo) throws Exception {
        this.checkParm(generalAuditVo);
        Page<GeneralHiTaskVo> page = new Page<>(generalAuditVo.getPage(), generalAuditVo.getSize());
        IPage<GeneralHiTaskVo> iPage = tbPamGeneralProcessTaskMapper.findHiTask(page, generalAuditVo);
        return iPage;
    }

    /**
     * 查询审核历史
     *
     * @author 苏小林
     * @date 2021/1/29 10:26
     * @param: generalAuditVo
     * @return: com.baomidou.mybatisplus.core.metadata.IPage<com.xhsj.user.generalprocess.vo.GeneralAuditHistoryVo>
     */
    public IPage<GeneralAuditHistoryVo> findAuditHistory(GeneralAuditVo generalAuditVo) throws Exception {
        this.checkParm(generalAuditVo);
        Page<GeneralHiTaskVo> page = new Page<>(generalAuditVo.getPage(), generalAuditVo.getSize());

        IPage<GeneralAuditHistoryVo> iPage = tbPamGeneralProcessTaskMapper.findAuditHistory(page, generalAuditVo);

        return iPage;
    }

    public void handleComputerRoomAccessApplyExamine_3(GeneralAuditVo generalAuditVo) throws Exception {
        this.checkParm(generalAuditVo);
        // 1.删除当前正在执行流程
        Long processTaskId = generalAuditVo.getProcessTaskId();
        tbPamGeneralProcessTaskMapper.delById(processTaskId, generalAuditVo.getTaskTableName());
        // 2.修改历史任务执行状态
       updateHiTask(generalAuditVo, processTaskId);
    }
}
